<?php

// 公共助手函数

/**
 * 处理插件钩子
 * @param string $hook 钩子名称
 * @param mixed $params 传入参数
 * @return void
 */
function hook($hook, $params = [])
{
    Hook::listen($hook, $params);
}

if (!function_exists('__')) {

    /**
     * 获取语言变量值
     * @param string $name 语言变量名
     * @param array $vars 动态变量值
     * @param string $lang 语言
     * @return mixed
     */
    function __($name, $vars = [], $lang = '')
    {
        if (is_numeric($name) || !$name)
            return $name;
        if (!is_array($vars)) {
            $vars = func_get_args();
            array_shift($vars);
            $lang = '';
        }
        return \think\facade\Lang::get($name, $vars, $lang);
    }

}

if (!function_exists('format_bytes')) {

    /**
     * 将字节转换为可读文本
     * @param int $size 大小
     * @param string $delimiter 分隔符
     * @return string
     */
    function format_bytes($size, $delimiter = '')
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 6; $i++)
            $size /= 1024;
        return round($size, 2) . $delimiter . $units[$i];
    }

}

if (!function_exists('datetime')) {

    /**
     * 将时间戳转换为日期时间
     * @param int $time 时间戳
     * @param string $format 日期时间格式
     * @return string
     */
    function datetime($time, $format = 'Y-m-d H:i:s')
    {
        $time = is_numeric($time) ? $time : strtotime($time);
        return date($format, $time);
    }

}

if (!function_exists('human_date')) {

    /**
     * 获取语义化时间
     * @param int $time 时间
     * @param int $local 本地时间
     * @return string
     */
    function human_date($time, $local = null)
    {
        return \neteast\Date::human($time, $local);
    }

}

if (!function_exists('cdnurl')) {

    /**
     * 获取上传资源的CDN的地址
     * @param string $url 资源相对地址
     * @param boolean $domain 是否显示域名 或者直接传入域名
     * @return string
     */
    function cdnurl($url, $domain = false)
    {
        $url = preg_match("/^https?:\/\/(.*)/i", $url) ? $url : \think\facade\Config::get('upload.cdnurl') . $url;
        if ($domain && !preg_match("/^(http:\/\/|https:\/\/)/i", $url)) {
            if (is_bool($domain)) {
                $public = \think\facade\Config::get('template.tpl_replace_string.__PUBLIC__');
                $url = rtrim($public, '/') . $url;
                if (!preg_match("/^(http:\/\/|https:\/\/)/i", $url)) {
                    $url = request()->domain() . $url;
                }
            } else {
                $url = $domain . $url;
            }
        }
        return $url;
    }

}


if (!function_exists('is_really_writable')) {

    /**
     * 判断文件或文件夹是否可写
     * @param    string $file 文件或目录
     * @return    bool
     */
    function is_really_writable($file)
    {
        if (DIRECTORY_SEPARATOR === '/') {
            return is_writable($file);
        }
        if (is_dir($file)) {
            $file = rtrim($file, '/') . '/' . md5(mt_rand());
            if (($fp = @fopen($file, 'ab')) === FALSE) {
                return FALSE;
            }
            fclose($fp);
            @chmod($file, 0777);
            @unlink($file);
            return TRUE;
        } elseif (!is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE) {
            return FALSE;
        }
        fclose($fp);
        return TRUE;
    }

}

if (!function_exists('rmdirs')) {

    /**
     * 删除文件夹
     * @param string $dirname 目录
     * @param bool $withself 是否删除自身
     * @return boolean
     */
    function rmdirs($dirname, $withself = true)
    {
        if (!is_dir($dirname))
            return false;
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($files as $fileinfo) {
            $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
            $todo($fileinfo->getRealPath());
        }
        if ($withself) {
            @rmdir($dirname);
        }
        return true;
    }

}

if (!function_exists('copydirs')) {

    /**
     * 复制文件夹
     * @param string $source 源文件夹
     * @param string $dest 目标文件夹
     */
    function copydirs($source, $dest)
    {
        if (!is_dir($dest)) {
            mkdir($dest, 0755, true);
        }
        foreach (
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item
        ) {
            if ($item->isDir()) {
                $sontDir = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName();
                if (!is_dir($sontDir)) {
                    mkdir($sontDir, 0755, true);
                }
            } else {
                copy($item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
            }
        }
    }

}

if (!function_exists('mb_ucfirst')) {

    function mb_ucfirst($string)
    {
        return mb_strtoupper(mb_substr($string, 0, 1)) . mb_strtolower(mb_substr($string, 1));
    }

}

if (!function_exists('addtion')) {

    /**
     * 附加关联字段数据
     * @param array $items 数据列表
     * @param mixed $fields 渲染的来源字段
     * @return array
     */
    function addtion($items, $fields)
    {
        if (!$items || !$fields)
            return $items;
        $fieldsArr = [];
        if (!is_array($fields)) {
            $arr = explode(',', $fields);
            foreach ($arr as $k => $v) {
                $fieldsArr[$v] = ['field' => $v];
            }
        } else {
            foreach ($fields as $k => $v) {
                if (is_array($v)) {
                    $v['field'] = isset($v['field']) ? $v['field'] : $k;
                } else {
                    $v = ['field' => $v];
                }
                $fieldsArr[$v['field']] = $v;
            }
        }
        foreach ($fieldsArr as $k => &$v) {
            $v = is_array($v) ? $v : ['field' => $v];
            $v['display'] = isset($v['display']) ? $v['display'] : str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
            $v['primary'] = isset($v['primary']) ? $v['primary'] : '';
            $v['column'] = isset($v['column']) ? $v['column'] : 'name';
            $v['model'] = isset($v['model']) ? $v['model'] : '';
            $v['table'] = isset($v['table']) ? $v['table'] : '';
            $v['name'] = isset($v['name']) ? $v['name'] : str_replace(['_ids', '_id'], '', $v['field']);
        }
        unset($v);
        $ids = [];
        $fields = array_keys($fieldsArr);
        foreach ($items as $k => $v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n]));
                }
            }
        }
        $result = [];
        foreach ($fieldsArr as $k => $v) {
            if ($v['model']) {
                $model = new $v['model'];
            } else {
                $model = $v['name'] ? \think\Db::name($v['name']) : \think\Db::table($v['table']);
            }
            $primary = $v['primary'] ? $v['primary'] : $model->getPk();
            $result[$v['field']] = $model->where($primary, 'in', $ids[$v['field']])->column("{$primary},{$v['column']}");
        }

        foreach ($items as $k => &$v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $curr = array_flip(explode(',', $v[$n]));

                    $v[$fieldsArr[$n]['display']] = implode(',', array_intersect_key($result[$n], $curr));
                }
            }
        }
        return $items;
    }

}

if (!function_exists('var_export_short')) {

    /**
     * 返回打印数组结构
     * @param string $var 数组
     * @param string $indent 缩进字符
     * @return string
     */
    function var_export_short($var, $indent = "")
    {
        switch (gettype($var)) {
            case "string":
                return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"';
            case "array":
                $indexed = array_keys($var) === range(0, count($var) - 1);
                $r = [];
                foreach ($var as $key => $value) {
                    $r[] = "$indent    "
                        . ($indexed ? "" : var_export_short($key) . " => ")
                        . var_export_short($value, "$indent    ");
                }
                return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
            case "boolean":
                return $var ? "TRUE" : "FALSE";
            default:
                return var_export($var, TRUE);
        }
    }

}

if (!function_exists('array_sort')) {
    /**
     * 二维数组排序
     * @param array $arr 需要排序的二维数组
     * @param string $keys 所根据排序的key
     * @param string $type 排序类型，desc、asc
     * @return array $new_array 排好序的结果
     */
    function array_sort($arr, $keys, $type = 'desc')
    {
        $key_value = $new_array = array();
        foreach ($arr as $k => $v) {
            $key_value[$k] = $v[$keys];
        }
        if ($type == 'asc') {
            asort($key_value);
        } else {
            arsort($key_value);
        }
        reset($key_value);
        foreach ($key_value as $k => $v) {
            $new_array[$k] = $arr[$k];
        }
        return $new_array;
    }
}

if (!function_exists('curl_post')) {
    /**
     * curl post请求
     *
     * @param      string  $url       The url
     * @param      string  $postdata  The postdata
     * @param      array   $options   The options
     *
     * @return     <type>  ( description_of_the_return_value )
     */
    function curl_post($url = '', $postdata = '', $options = array()) {
        // $url = str_replace(' ', '+', $url);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        $data = curl_exec($ch);
        // echo 'Errno'.curl_error($ch);
        curl_close($ch);
        return $data;
    }
}
if (!function_exists('is_json')) {
    /**
     * 判断字符串是否为 Json 格式
     * 
     * @param  string     $data  Json 字符串
     * @param  bool       $assoc 是否返回关联数组。默认返回对象
     * 
     * @return bool|array 成功返回转换后的对象或数组，失败返回 false
     */
    function is_json($data = '', $assoc = false) {
        $data = json_decode($data, $assoc);
        if ( $data && ( is_object($data) || is_array($data) ) ) {
            return $data;
        }
        return false;
    }
}
if (!function_exists('xmlToArray')) {
    /** 
     * 将xml转换为数组 
     * @param string $xml_str:xml字符串 
     * @param string $type:xml的不同格式，kv(叶子键值对，不带属性),att（叶子带属性，没有键值）,kv_att|att_kv（叶子即带属性，又带键值对） ；默认为att格式
     * @return array 
     */ 
    function xmlToArray($xml_str, $type='att'){  
        $arr = array();
        $obj = simplexml_load_string($xml_str);
        if($type == 'kv' || $type == 'att'){
            $arr = json_decode(json_encode($obj),true); 
        }else if($type == 'kv_att' || $type == 'att_kv'){
            $arr = xmlobjToArr($obj);
        }
        return $arr;  
    }
}
if (!function_exists('xmlobjToArr')) {
    /** 
     * 将xml对象转换为数组 
     * @param object $xmlObj:xml对象
     * @return array 
     */ 
    function xmlobjToArr($xmlObj){
        $arr = array();
        foreach ($xmlObj as $key => $value) {
            $json = json_encode($value);
            $item_arr = json_decode($json,true);
            if(isset($item_arr['@attributes'])){
                $item_arr['@node_value'] = $item_arr[0];
                unset($item_arr[0]);
                if(!isset($arr[$key])){
                    $arr[$key][0] = $item_arr;
                }else{
                    $length = count($arr[$key]);
                    $arr[$key][$length] = $item_arr;
                }
            }else{
                if(is_array($item_arr) && array_depth($item_arr) > 1){
                    if(!isset($arr[$key])){
                            $arr[$key] = xmlobjToArr($value);
                        }else{
                            if(isset($arr[$key][0])){
                                $length = count($arr[$key]);
                                $arr[$key][$length] = xmlobjToArr($value);
                            }else{
                                $temp = $arr[$key];
                                unset($arr[$key]);
                                $arr[$key][0] = $temp;
                                $arr[$key][1] = xmlobjToArr($value);
                            }
                        }
                }else{
                    if(!isset($arr[$key])){
                        $arr[$key] = $item_arr;
                    }else{
                        if(isset($arr[$key][0])){
                            $length = count($arr[$key]);
                            $arr[$key][$length] = $item_arr;
                        }else{
                            $temp = $arr[$key];
                            unset($arr[$key]);
                            $arr[$key][0] = $temp;
                            $arr[$key][1] = $item_arr;
                        }
                    }
                }
            }
        }
        return $arr;
    }
}
if (!function_exists('array_depth')) {
    /** 
     * 获取数组的维度 
     * @param array $a:数组
     * @return int 
     */ 
    function array_depth($a){
      $i=1;$j=1;
      foreach($a as $v){
          if(is_array($v)){
            $i=1+array_depth($v);
            if($j < $i){
               $j = $i;
             }
          }
        }
        return $j;
    }
}
if (!function_exists('arrayToXmlAuto')) {
    /** 
     * 将数组转换为xml 
     * @param array $arr:数组 
     * @param string $type:xml的不同格式，kv(叶子键值对，不带属性),att（叶子带属性，没有键值）,kv_att|att_kv（叶子即带属性，又带键值对） ；默认为att格式
     * @param string $root:根节点名称 
     * @param object $dom:Document对象，默认null即可 
     * @param object $node:节点对象，默认null即可 
     * @param string $cdata:是否加入CDATA标签，默认为false 
     * @param string $attribute_node:带标签属性的节点名，默认为空
     * @return string 
     */  
    function arrayToXmlAuto($arr,$type='att',$root='xml',$dom=null,$node=null,$cdata=false,$attribute_node=''){  
        if (!$dom){  
            $dom = new DOMDocument('1.0','utf-8');  
            $dom->formatOutput = true;
        }  
        if(!$node){  
            $node = $dom->createElement($root);  
            $dom->appendChild($node);  
        }  
        foreach ($arr as $key=>$value){  
            if($key === '@attributes'){
                foreach ($value as $key3 => $value3) {
                    $invalid_attr = $dom->createAttribute($key3);
                    $invalid_attr->value = $value[$key3];
                    $node->appendChild($invalid_attr); 
                }
            }else{
                if(is_array($value)){
                    if(is_numeric(key($value))){
                        $child_node = $node;
                    }else{
                        $keys = array_keys($value);
                        if($type == 'att' && in_array('@attributes', $keys) && in_array(0, $keys)){
                            unset($value[0]);
                        }
                        $child_node = $dom->createElement(is_string($key) ? $key : $attribute_node);  
                        // var_dump('==node=='.$node->tagName);
                        // var_dump('==child_node=='.$child_node->tagName);
                        if($type == 'att_kv' || $type == 'kv_att'){
                            if(is_numeric($key)){
                                //把下级的value值给赋值上
                                $text_node = getChildNodeValue($value);
                                $data = $dom->createTextNode($text_node); 
                                $child_node->appendChild($data); 
                            }
                        }
                        $node->appendChild($child_node);
                    }
                    arrayToXmlAuto($value,$type,$root,$dom,$child_node,$cdata,$key);  
                }else{
                    if($type == 'att_kv' || $type == 'kv_att'){
                        if($key == '@node_value'){
                            continue;
                        }
                    }
                    $child_node = $dom->createElement(is_string($key) ? $key : $attribute_node);
                    $node->appendChild($child_node);
                    if (!$cdata) {  
                        $data = $dom->createTextNode($value);  
                    }else{  
                        $data = $dom->createCDATASection($value);  
                    }  
                    $child_node->appendChild($data);  
                }
            }  
        }  
        return $dom->saveXML();  
    }
}
if (!function_exists('getChildNodeValue')) {
    /** 
     * 获取xml数组最后一层节点的值
     * @param array $arr:xml数组最后一个节点数组 
     * @return string 
     */ 
    function getChildNodeValue($arr){
        foreach ($arr as $key => $value) {
            if($key === '@node_value'){
                return $value;
            }
        }
        return '获取失败~';
    }
}
if (!function_exists('arrayToXml')) {
    //数组转成xml
    function arrayToXml($arr, $root_name_start='', $root_name_close=''){ 
        // return 1;exit;
        $xml = $root_name_start;
        foreach ($arr as $key=>$val){ 
            if(is_array($val)){ 
                if(is_numeric($key)){
                    $xml.= arrayToXml($val); 
                }else{
                    $xml.="<".$key.">".arrayToXml($val)."</".$key.">";
                } 
            }else{ 
                if(is_numeric($key)){
                    $xml.= $val; 
                }else{
                    $xml.="<".$key.">".$val."</".$key.">"; 
                }
            } 
        } 
        $xml.=$root_name_close;  
        return $xml; 
    }
}
if (!function_exists('conversion_unit')) {
    // 1TB=1024GB
    // 1GB=1024MB
    // 1MB=1024KB
    // 1KB=1024Byte
    function conversion_unit($text){
        $number = $text;
        if(strpos($text, 'T') !== false){
            $number = str_replace('T', '', $text);
            $number = 1024*1024*1024*1024*$number;
        }else if(strpos($text, 'G') !== false){
            $number = str_replace('G', '', $text);
            $number = 1024*1024*1024*$number;
        }else if(strpos($text, 'M') !== false){
            $number = str_replace('M', '', $text);
            $number = 1024*1024*$number;
        }else if(strpos($text, 'K') !== false){
            $number = str_replace('K', '', $text);
            $number = 1024*$number;
        }
        return sprintf('%.2f',$number);
    }
}
if (!function_exists('conversion_unit_text')) {
    // 1TB=1024GB
    // 1GB=1024MB
    // 1MB=1024KB
    // 1KB=1024Byte
    function conversion_unit_text($number, $unit=''){
        $text = $number;
        $KB = 1024;
        $MB = $KB*1024;
        $GB = $MB*1024;
        $TB = $GB*1024;
        if($unit == 'T'){
            $text = round($number/$TB,2);
        }else if($unit == 'G'){
            $text = round($number/$GB,2);
        }else if($unit == 'M'){
            $text = round($number/$MB,2);
        }else if($unit == 'K'){
            $text = round($number/$KB,2);
        }else{ //自动转
            if($number<$KB){
                return $number.'B';
            }else if($number<$MB){
                return round($number/$KB,2).'KB';
            }elseif($number<$GB){
                return round($number/$MB,2).'MB';
            }elseif($number<$TB){
                return round($number/$GB,2).'GB';
            }else{
                return round($number/$TB,2).'TB';
            }
        }
        return $text.$unit;
    }
}

if (!function_exists('converBToStandard')) {
    //转化B到KB\mB\GB\TB
    function converBToStandard($bInt) {
        $bInt = is_numeric($bInt)?$bInt:0;
        if ($bInt < 1024) {
            return round($bInt, 2) . 'B';
        } elseif (($bInt /= 1024) < 1024) {          //在1KB~1MB之间
            return round($bInt, 2) . 'KB';
        } elseif (($bInt /= 1024) < 1024) {        //在1MB~1GB之间        
            return round($bInt, 2) . 'MB';
        } elseif (($bInt /= 1024) < 1024) {        //在1GB~1TB之间        
            return round($bInt, 2) . 'GB';
        } elseif (($bInt /= 1024) < 1024) {        //在1TB~1PB之间        
            return round($bInt, 2) . 'TB';
        } elseif (($bInt /= 1024) < 1024) {        //在1PB~1EB之间        
            return round($bInt, 2) . 'PB';
        } elseif (($bInt /= 1024) < 1024) {        //在1EB~1ZB之间  
            return round($bInt, 2) . 'EB';
        } else {                              //1ZB以上
            $bInt /= 1024;
            return round($bInt, 2) . 'ZB';
        }
    }
}